using System;
using System.Collections;
using System.Collections.Generic;
using NFreeMarker.Core;
using NFreeMarker.Ext.Util;
using NFreeMarker.Template;
using NFreeMarker.Template.Utility;

namespace NFreeMarker.Ext.Beans
{
    /**
     * Model used by {@link BeansWrapper} when <tt>simpleMapWrapper</tt>
     * mode is enabled. Provides a simple hash model interface to the
     * underlying map (does not copy like {@link freemarker.template.SimpleHash}),
     * and a method interface to non-string keys.
     * @author Chris Nokleberg
     * @version $Id: SimpleMapModel.java,v 1.9 2005/06/12 19:03:04 szegedia Exp $
     */
    public class SimpleMapModel : WrappingTemplateModel, ITemplateHashModelEx, ITemplateMethodModelEx, IAdapterTemplateModel, IWrapperTemplateModel 
    {
        internal static readonly IModelFactory Factory = new ModelFactoryImpl();

        internal class ModelFactoryImpl : IModelFactory
        {
            public ITemplateModel Create(object obj, IObjectWrapper wrapper)
            {
                return new SimpleMapModel((IDictionary) obj, (BeansWrapper) wrapper);
            }
        }

        private readonly IDictionary _map;
        
        public SimpleMapModel(IDictionary map, BeansWrapper wrapper)
            : base(wrapper)
        {
            _map = map;
        }

        public ITemplateModel Get(string key)
        {
            object val = _map.GetValueOrDefault(key);
            if (val == null)
            {
                if (key.Length == 1)
                {
                    // just check for Character key if this is a single-character string
                    char charKey = key[0];
                    val = _map.GetValueOrDefault(charKey);
                    if (val == null && !(_map.Contains(key) || _map.Contains(charKey)))
                    {
                        return null;
                    }
                }
                else if (!_map.Contains(key))
                {
                    return null;
                }
            }
            return Wrap(val);
        }
        
        public object Exec(IList<ITemplateModel> args)
        {
            object key = ((BeansWrapper) GetObjectWrapper()).Unwrap(args[0]);
            object value = _map.GetValueOrDefault(key);
            if (value == null && !_map.Contains(key))
            {
                return null;
            }
            return Wrap(value);
        }

        public object Exec(IList<string> arguments)
        {
            throw new NotSupportedException();
        }

        public bool IsEmpty()
        {
            return _map.Count == 0;
        }

        public int Size()
        {
            return _map.Count;
        }

        public ITemplateCollectionModel Keys()
        {
            return new CollectionAndSequence(new SimpleSequence(_map.Keys, GetObjectWrapper()));
        }

        public ITemplateCollectionModel Values()
        {
            return new CollectionAndSequence(new SimpleSequence(_map.Values, GetObjectWrapper()));
        }
        
        public object GetAdaptedObject(Type hint)
        {
            return _map;
        }
        
        public object GetWrappedObject()
        {
            return _map;
        }
    }
}